<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="root">
    <div>
      <div>hello1</div>
      <div>hello2</div>
      <div>hello3</div>
      <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
      </ul>
    </div>
  </div>

  <script>
    /*
    为什么要使用虚拟dom？？？提高性能
    直接操作页面dom，页面会不断更新，更新dom会造成页面刷新和页面内存控制
    很消耗性能，虚拟dom所有的操作都是在内存中，虚拟dom的操作完成后
    更新到页面上只需要更新一次就可以了。虚拟dom是缓存起来的。

    vnode和真实dom的转换
    <div /> { tag: 'div' }
    文本节点  { tag: undefined, value: '文本' }
    <div title="1" class="c" /> { tag: 'div', data: { title: '1', class: 'c' }} }
    <div><div/></div>  { tag: 'div', children: [ {tag: 'div'} ] }
    */

    class VNode {
      constructor(tag,data,value,type) {
        this.tag = tag && tag.toLowerCase();// 文本的话tag为undefined
        this.data = data;
        this.value = value;
        this.type = type;
        this.children = [];
      }
      appendChild(vnode) {
        this.children.push(vnode)
      }
    }
    /*
    将真是dom转化为vnode
    使用递归， 来遍历dom元素，生成虚拟dom，
    vue中的源码使用的栈结构，使用栈存储父元素来实现递归生成
    */
    function getVNode(node) {
      let nodeType = node.nodeType; // 元素类型，1.文本 3.元素
      let _vnode = null;
      if(nodeType ===1) {
        // 元素
        let nodeName = node.nodeName;
        let attrs = node.attributes; // 伪数组
        let _attrObj = {};
        for(let i=0; i<attrs.length; i++) { // attrs[i] 属性节点，nodeType：2
          _attrObj[attrs[i].nodeName] = attrs[i].nodeValue;
        }
        _vnode = new VNode(nodeName, _attrObj, undefined, nodeType)

        // 考虑node真是dom的子元素
        let childNodes = node.childNodes;
        for(let i=0; i<childNodes.length; i++) {
          _vnode.appendChild(getVNode(childNodes[i])) // 递归
        }

      } else if(nodeType ===3) {
        // 文本
        _vnode = new VNode(undefined, undefined, node.nodeValue,nodeType)
      }
      return _vnode
    }

    let root = document.querySelector('#root')
    let vroot = getVNode(root)
    console.log(vroot)

    // 把vnode转化为真正的dom
    function parseVNode(vnode) {
      // 创建真实dom
      let type = vnode.type;
      let _node = null;
      if(type === 3) {
        return document.createTextNode(vnode.value)
      } else if(type === 1) { // 创建元素
        _node = document.createElement(vnode.tag)
        // 属性
        let data = vnode.data;// 属性是键值对
        Object.keys(data).forEach(key => {
          let attrName = key;
          let attrValue = data[key];
          _node.setAttribute(attrName, attrValue)
        })

        // 子元素
        let children = vnode.children;
        children.forEach(subnode => {
          // 子元素subnode 虚拟dom，递归转换子元素
          _node.appendChild(parseVNode(subnode))
        })
        return _node;
      }
    }

    let div = parseVNode(vroot)
    console.log(div)
  </script>
</body>
</html>